延續前幾天的向量資料庫理論,今天動手實作。分別用 Qdrant(原生向量資料庫)跟 pgvector(PostgreSQL 擴充套件)跑一次完整流程:安裝 → 建立 collection/table → 寫入向量 → 查詢 → 加上 Metadata Filtering。
啟動 Qdrant(用 Docker 最快)
docker run -p 6333:6333 -p 6334:6334 qdrant/qdrant
啟動後可以打開 http://localhost:6333/dashboard 看到管理介面。
安裝 Python SDK
pip install qdrant-client
建立 Collection
Qdrant 的「collection」概念類似關聯式資料庫的 table,但存的是向量。
from qdrant_client import QdrantClient
from qdrant_client.models import Distance, VectorParams
client = QdrantClient(url="http://localhost:6333")
client.create_collection(
collection_name="my_documents",
vectors_config=VectorParams(size=768, distance=Distance.COSINE)
# size 要跟你的 Embedding 模型輸出維度一致
#distance 可選 COSINE / EUCLID / DOT
)
寫入向量(含 Metadata)
from qdrant_client.models import PointStruct
points = [
PointStruct(
id=1,
vector=[0.05, 0.61, 0.76, ...], # 你的 embedding 結果
payload={"text": "向量資料庫適合語意搜尋", "category": "database", "year": 2024}
),
PointStruct(
id=2,
vector=[0.19, 0.81, 0.75, ...],
payload={"text": "PostgreSQL 是關聯式資料庫", "category": "database", "year": 2023}
),
]
client.upsert(collection_name="my_documents", points=points)
查詢(找最相似的向量)
query_vector = [0.05, 0.60, 0.75, ...] # 使用者問題轉成的向量
results = client.query_points(
collection_name="my_documents",
query=query_vector,
limit=3
)
for point in results.points:
print(point.score, point.payload)
加上 Metadata Filtering
比如「只搜尋 2024 年之後、且分類是 database 的資料」:
from qdrant_client.models import Filter, FieldCondition, MatchValue, Range
results = client.query_points(
collection_name="my_documents",
query=query_vector,
query_filter=Filter(
must=[
FieldCondition(key="category", match=MatchValue(value="database")),
FieldCondition(key="year", range=Range(gte=2024))
]
),
limit=3
)
適合已經有 PostgreSQL 環境、不想再多引入一套系統的情況。
安裝擴充套件
CREATE EXTENSION IF NOT EXISTS vector;
(若用 Docker,可以直接用官方映像檔 pgvector/pgvector:pg16)
建立資料表
CREATE TABLE documents (
id SERIAL PRIMARY KEY,
content TEXT,
category TEXT,
created_year INT,
embedding VECTOR(768) -- 維度需與你的 Embedding 模型一致
);
建立索引(加速查詢,等同於 HNSW)
CREATE INDEX ON documents
USING hnsw (embedding vector_cosine_ops);
pgvector 也支援 vector_l2_ops(歐氏距離)跟 vector_ip_ops(內積),依需求選擇。
寫入資料
INSERT INTO documents (content, category, created_year, embedding)
VALUES ('向量資料庫適合語意搜尋', 'database', 2024, '[0.05, 0.61, 0.76, ...]');
Python 端也可以用 psycopg2 或 SQLAlchemy 批次寫入。
查詢最相似的資料
SELECT content, category, 1 - (embedding <=> '[0.05, 0.60, 0.75, ...]') AS similarity
FROM documents
ORDER BY embedding <=> '[0.05, 0.60, 0.75, ...]'
LIMIT 3;
<=> 是 pgvector 的餘弦距離運算子(距離越小越相似,所以用 1 - 轉成相似度好理解)。
加上 Metadata Filtering
SELECT content, category, created_year
FROM documents
WHERE category = 'database' AND created_year >= 2024
ORDER BY embedding <=> '[0.05, 0.60, 0.75, ...]'
LIMIT 3;
| 情境 | Qdrant | pgvector |
|---|---|---|
| 查詢語法 | 專用 Python/REST API | 標準 SQL |
| Metadata Filtering | 需用 Filter/FieldCondition 物件 | 直接 WHERE 子句 |
| 部署 | 需獨立服務(Docker/雲端) | 掛在既有 PostgreSQL 上 |
| 適合情境 | 專案獨立、追求效能 | 已有 PostgreSQL 基礎設施 |